/*
 * Copyright 2001 Alexander Boverman and the original authors.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef _WT_TABLE_H
#define _WT_TABLE_H

#include <tcl.h>

/* Table data */

typedef struct WtTableT {
  Tcl_HashTable items;
} WtTable;

/* Generic table functions */

int WtTableSize(Tcl_Obj *tbl);
int WtTableHas(Tcl_Obj *tbl, Tcl_Obj *key);
Tcl_Obj *WtTableGet(Tcl_Obj *tbl, Tcl_Obj *key);
Tcl_Obj *WtTableGetDefault(Tcl_Obj *tbl, Tcl_Obj *key,
  Tcl_Obj *fallback);
int WtTableGetFirst(Tcl_Obj *tbl, Tcl_Obj *key, Tcl_Obj **val,
  Tcl_Interp *interp);
int WtTableGetFirstDefault(Tcl_Obj *tbl, Tcl_Obj *key,
  Tcl_Obj **val, Tcl_Obj *fallback, Tcl_Interp *interp);
int WtTableGetList(Tcl_Obj *tbl, Tcl_Obj *key, Tcl_Obj **list,
  Tcl_Interp *interp);
int WtTableGetListDefault(Tcl_Obj *tbl, Tcl_Obj *key,
  Tcl_Obj **list, Tcl_Obj *fallback, Tcl_Interp *interp);
void WtTableSet(Tcl_Obj *tbl, Tcl_Obj *key, Tcl_Obj *val);
void WtTableSetInternal(WtTable *tbl, Tcl_Obj *key, Tcl_Obj *val);
void WtTableSetDefault(Tcl_Obj *tbl, Tcl_Obj *key, Tcl_Obj *val,
  Tcl_Obj **result);
void WtTableSetOneValueList(Tcl_Obj *tbl, Tcl_Obj *key,
  Tcl_Obj *val, Tcl_Obj **result);
void WtTableSetOneValueListDefault(Tcl_Obj *tbl, Tcl_Obj *key,
  Tcl_Obj *val, Tcl_Obj **result);
int WtTableAppendToList(Tcl_Obj *tbl, Tcl_Obj *key,
  Tcl_Obj *val, Tcl_Obj **list, Tcl_Interp *interp);
int WtTableAppendListToList(Tcl_Obj *tbl, Tcl_Obj *key,
  Tcl_Obj *valList, Tcl_Obj **list, Tcl_Interp *interp);
int WtTableAppendToListInternal(Tcl_Obj *tbl, Tcl_Obj *key,
  Tcl_Obj *val, int multipleVals, Tcl_Obj **list,
  Tcl_Interp *interp);
int WtTableKeys(Tcl_Obj *tbl, Tcl_Obj **keys, Tcl_Interp *interp);
int WtTableValues(Tcl_Obj *tbl, Tcl_Obj **vals, Tcl_Interp *interp);
int WtTableFirstValues(Tcl_Obj *tbl, Tcl_Obj **vals,
  Tcl_Interp *interp);
void WtTableRemove(Tcl_Obj *tbl, Tcl_Obj *key);
int WtTableRemoveList(Tcl_Obj *tbl, Tcl_Obj *list,
  Tcl_Interp *interp);
int WtUpdateTable(Tcl_Obj *dest, Tcl_Obj *src);
void WtClearTable(Tcl_Obj *tbl);
int WtConvertToTableObj(Tcl_Obj *obj, Tcl_ObjType *type, Tcl_Interp *interp);
void WtInitTableItems(WtTable *tbl, Tcl_ObjType *type);
void WtDeleteTableItems(WtTable *tbl);
WtTable *WtTableRep(Tcl_Obj *tblObj);
Tcl_HashTable *WtGetTableMap(Tcl_Obj *tblObj);
int WtIsTableType(Tcl_ObjType *type);

/* Standard table object */

Tcl_Obj *WtNewTableObj();
void WtFreeTable(Tcl_Obj *tbl);
void WtDupTable(Tcl_Obj *src, Tcl_Obj *dest);
void WtUpdateTableString(Tcl_Obj *tbl);
int WtSetTableFromAny(Tcl_Interp *interp, Tcl_Obj *obj);
int WtConvertToTable(Tcl_Obj *obj, Tcl_Interp *interp);

/* Case-insensitive table object */

Tcl_Obj *WtNewCaselessTableObj();
void WtFreeCaselessTable(Tcl_Obj *tbl);
void WtDupCaselessTable(Tcl_Obj *src, Tcl_Obj *dest);
void WtUpdateCaselessTableString(Tcl_Obj *tbl);
int WtSetCaselessTableFromAny(Tcl_Interp *interp, Tcl_Obj *obj);
int WtConvertToCaselessTable(Tcl_Obj *obj, Tcl_Interp *interp);
unsigned int HashCaselessKey(Tcl_HashTable *hashTable, void *keyPtr);
int CompareCaselessKeys(void *keyPtr, Tcl_HashEntry *entry);
Tcl_HashEntry *AllocCaselessEntry(Tcl_HashTable *hashTable, void *keyPtr);
void FreeCaselessEntry(Tcl_HashEntry *ent);

/* Type-guarded table functions */

Tcl_Obj *WtNewTableObjWithType(Tcl_ObjType *type);
Tcl_Obj *WtNewTableObjWithElements(Tcl_ObjType *type,
  int objc, const Tcl_Obj *objv[], Tcl_Interp *interp);
int WtTableObjSize(Tcl_Obj *tbl, int *size, Tcl_ObjType *type,
  Tcl_Interp *interp);
int WtTableObjHas(Tcl_Obj *tbl, Tcl_Obj *key, int *has,
  Tcl_ObjType *type, Tcl_Interp *interp);
int WtTableObjGet(Tcl_Obj *tbl, Tcl_Obj *key, Tcl_Obj **val,
  Tcl_ObjType *type, Tcl_Interp *interp);
int WtTableObjGetDefault(Tcl_Obj *tbl, Tcl_Obj *key, Tcl_Obj **val,
  Tcl_Obj *fallback, Tcl_ObjType *type, Tcl_Interp *interp);
int WtTableObjGetFirst(Tcl_Obj *tbl, Tcl_Obj *key, Tcl_Obj **val,
  Tcl_ObjType *type, Tcl_Interp *interp);
int WtTableObjGetFirstDefault(Tcl_Obj *tbl, Tcl_Obj *key,
  Tcl_Obj **val, Tcl_Obj *fallback, Tcl_ObjType *type,
  Tcl_Interp *interp);
int WtTableObjGetList(Tcl_Obj *tbl, Tcl_Obj *key, Tcl_Obj **list,
  Tcl_ObjType *type, Tcl_Interp *interp);
int WtTableObjGetListDefault(Tcl_Obj *tbl, Tcl_Obj *key,
  Tcl_Obj **list, Tcl_Obj *fallback, Tcl_ObjType *type,
  Tcl_Interp *interp);
int WtTableObjSetDefault(Tcl_Obj *tbl, Tcl_Obj *key, Tcl_Obj *val,
  Tcl_Obj **result, Tcl_ObjType *type, Tcl_Interp *interp);
int WtTableObjSetOneValueList(Tcl_Obj *tbl, Tcl_Obj *key,
  Tcl_Obj *val, Tcl_Obj **result, Tcl_ObjType *type,
  Tcl_Interp *interp);
int WtTableObjSetOneValueListDefault(Tcl_Obj *tbl, Tcl_Obj *key,
  Tcl_Obj *val, Tcl_Obj **result, Tcl_ObjType *type,
  Tcl_Interp *interp);
int WtTableObjAppendToList(Tcl_Obj *tbl, Tcl_Obj *key,
  Tcl_Obj *val, Tcl_Obj **list, Tcl_ObjType *type,
  Tcl_Interp *interp);
int WtTableObjAppendListToList(Tcl_Obj *tbl, Tcl_Obj *key,
  Tcl_Obj *valList, Tcl_Obj **list, Tcl_ObjType *type,
  Tcl_Interp *interp);
int WtTableObjKeys(Tcl_Obj *tbl, Tcl_Obj **keys, Tcl_ObjType *type,
  Tcl_Interp *interp);
int WtTableObjValues(Tcl_Obj *tbl, Tcl_Obj **vals,
  Tcl_ObjType *type, Tcl_Interp *interp);
int WtTableObjFirstValues(Tcl_Obj *tbl, Tcl_Obj **vals,
  Tcl_ObjType *type, Tcl_Interp *interp);
int WtTableObjRemove(Tcl_Obj *tbl, Tcl_Obj *key,
  Tcl_ObjType *type, Tcl_Interp *interp);
int WtTableObjRemoveList(Tcl_Obj *tbl, Tcl_Obj *list,
  Tcl_ObjType *type, Tcl_Interp *interp);
int WtClearTableObj(Tcl_Obj *tbl, Tcl_ObjType *type, Tcl_Interp *interp);

/* Common type handlers */

void WtFreeTableObj(Tcl_Obj *tbl);
void WtDupTableObj(Tcl_Obj *src, Tcl_Obj *dest);
void WtUpdateTableObjString(Tcl_Obj *tbl);
int WtSetTableObjFromAny(Tcl_Interp *interp, Tcl_Obj *obj,
  Tcl_ObjType *type);

/* Globals */

extern struct Tcl_ObjType WtTableType;
extern struct Tcl_ObjType WtCaselessTableType;
extern Tcl_HashKeyType WtCaselessHashKeyType;

#endif /* ! _WT_TABLE_H */
